package com.thinkit.bigdata.web.service.impl.statistics;

import com.alibaba.fastjson.JSON;
import com.google.common.base.Strings;
import com.thinkit.bigdata.core.ConfigHelper;
import com.thinkit.bigdata.core.util.CastUtil;
import com.thinkit.bigdata.core.util.TaskUtil;
import com.thinkit.bigdata.core.util.es.ESUtil;
import com.thinkit.bigdata.web.controller.pubmet.PubMethod;
import com.thinkit.bigdata.web.coremet.SystemStatic;
import com.thinkit.bigdata.web.dao.bus.BusTagMapper;
import com.thinkit.bigdata.web.model.BaseEntity;
import com.thinkit.bigdata.web.model.bus.BusTag;
import com.thinkit.bigdata.web.model.es.audioEs.BusinessTags;
import com.thinkit.bigdata.web.model.es.audioEs.Source;
import com.thinkit.bigdata.web.model.result.HtmlResult;
import com.thinkit.bigdata.web.service.audioSearch.AudioSearchPubMet;
import com.thinkit.bigdata.web.service.statistics.TagStatisticsServer;
import org.apache.log4j.Logger;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

@Service
public class TagStatisticsServiceImpl implements TagStatisticsServer {

    private static Logger logger = Logger.getLogger(TagStatisticsServiceImpl.class);

    @Resource
    private ESUtil esUtil;

    @Resource
    private BusTagMapper tagMapper;

    @Resource
    private AudioSearchPubMet searchPubMet;

    private Map<String, Integer> sumSysAndTelTags(String tagName, HttpServletRequest request, int proType) {
        //系统打标量
        List<Source> tagSourceList = new ArrayList<>();
        String[] includes = new String[]{"serialNumber", "callTags"};
        if (BaseEntity.PROTYPE_ZX == proType) {
            //总条数
            Integer sum = SystemStatic.crud.queryQBuilderAllByMes(SystemStatic.AUDIO_ES_INDEX,
                    SystemStatic.AUDIO_ES_TYPE,
                    getTelTagQueByName(request, tagName)
            );
            //单词查询条数
            int excleMax = ConfigHelper.getInt("export.data.sheet.max.number", 1000);
            List<Integer> pageTout = TaskUtil.formatSum(sum, excleMax);//todo最后一个数字需要特殊处理:6022
            for (Integer aPageTout : pageTout) {
                List<String> docList = SystemStatic.crud.queryQBuilderByMes(
                        SystemStatic.AUDIO_ES_INDEX,
                        SystemStatic.AUDIO_ES_TYPE,
                        aPageTout,
                        excleMax,
                        getTelTagQueByName(request, tagName),
                        includes
                );
                if (docList.isEmpty()) continue;
                tagSourceList.addAll(esUtil.strs2Entitys(docList));
            }
        } else {
            //单词查询条数
            int excleMax = ConfigHelper.getInt("export.data.sheet.max.number", 1000);
            // 系统打标量
            //总条数
            Integer sum = SystemStatic.crud.queryQBuilderAllByMes(SystemStatic.AUDIO_ES_INDEX,
                    SystemStatic.AUDIO_ES_TYPE,
                    getSysTagQueByName(request, tagName)
            );
            List<Integer> pageTout = TaskUtil.formatSum(sum, excleMax);//todo最后一个数字需要特殊处理:6022
            for (Integer aPageTout : pageTout) {
                List<String> docList = SystemStatic.crud.queryQBuilderByMes(
                        SystemStatic.AUDIO_ES_INDEX,
                        SystemStatic.AUDIO_ES_TYPE,
                        aPageTout,
                        excleMax,
                        getSysTagQueByName(request, tagName),
                        includes
                );
                if (docList.isEmpty()) continue;
                tagSourceList.addAll(esUtil.strs2Entitys(docList));
            }
        }
        return formatResMap(tagSourceList, proType, tagName, "all");
    }

    private Map<String, Integer> sumSysTagAll(HttpServletRequest request) {
        List<Source> allTags = new ArrayList<>();
        //单词查询条数
        int excleMax = ConfigHelper.getInt("export.data.sheet.max.number", 1000);
        // 系统打标量
        String[] includes = new String[]{"serialNumber", "callTags"};
        //总条数
        Integer sum1 = SystemStatic.crud.queryQBuilderAllByMes(SystemStatic.AUDIO_ES_INDEX,
                SystemStatic.AUDIO_ES_TYPE,
                getSysTagAllQue(request)
        );
        List<Integer> pageTout1 = TaskUtil.formatSum(sum1, excleMax);//todo最后一个数字需要特殊处理:6022
        for (Integer aPageTout : pageTout1) {
            List<String> docList = SystemStatic.crud.queryQBuilderByMes(
                    SystemStatic.AUDIO_ES_INDEX,
                    SystemStatic.AUDIO_ES_TYPE,
                    aPageTout,
                    excleMax,
                    getSysTagAllQue(request),
                    includes
            );
            if (docList.isEmpty()) continue;
            allTags.addAll(esUtil.strs2Entitys(docList));
        }
        return formatResMap(allTags, BaseEntity.PROTYPE_ZJ, "", "");
    }

    private static Map<String, Integer> formatResMap(List<Source> sourceList, int proType, String tagName, String methodT) {
        //去重Source
        List<String> serialNumberList = new ArrayList<>();
        //纠正数量(人工修改)
        int corTagCount = 0;
        //人工新增量
        int addTagCount = 0;
        //系统打标量
        int sysTagCount = 0;
        //总打标量
        int tagCount = 0;
        for (Source source : sourceList) {
            if (source.getCallTags() == null) continue;
            //该条id已存在去重集合中，为重复数据
            if (serialNumberList.contains(source.getSerialNumber())) continue;
            //该条记录计算后，加入去重集合
            serialNumberList.add(source.getSerialNumber());
            for (BusinessTags tags : source.getCallTags()) {
                if (!Strings.isNullOrEmpty(methodT) && !tags.getTagName().contains(tagName)) continue;
                if (BaseEntity.PROTYPE_ZX != proType) {
                    if (tags.getProType() == BaseEntity.PROTYPE_ZJ) {//系统打标量
                        addTagCount++;
                        if (tags.getProValue() == BaseEntity.PROVALUE_NO) {
                            corTagCount++;
                        }
                    }
                    if (tags.getProType() == BaseEntity.PROTYPE_SYS) {//人工新增量
                        sysTagCount++;
                        if (tags.getProValue() == BaseEntity.PROVALUE_NO) {
                            corTagCount++;
                        }
                    }
                } else {
                    if (tags.getProType() == BaseEntity.PROTYPE_ZX) {
                        tagCount++;
                    }
                }
            }
        }
        Map<String, Integer> countMap = new HashMap<>();
        if (BaseEntity.PROTYPE_ZX == proType) {
            countMap.put("tagCount", tagCount);
        } else {
            countMap.put("sysTagCount", sysTagCount);
            countMap.put("addTagCount", addTagCount);
            countMap.put("corTagCount", corTagCount);
            countMap.put("tagCount", (sysTagCount + addTagCount - corTagCount));
        }
        return countMap;
    }

    private static void contMap (Map<String, String> resultMap, Map<String, Integer> countMap, String type) {
        //打标数量
        int tagCount = countMap.get("tagCount");
        resultMap.put("tagCount", tagCount + "");
        if ("sys".equals(type)) {
            //纠正数量(人工修改)
            int corTagCount = countMap.get("corTagCount");
            //人工新增量
            int addTagCount = countMap.get("addTagCount");
            //系统打标量
            int sysTagCount = countMap.get("sysTagCount");
            resultMap.put("tagType", "1,2");
            resultMap.put("tagName", "-");
            resultMap.put("sysTagCount", sysTagCount + "");
            resultMap.put("addTagCount", addTagCount + "");
            resultMap.put("corTagCount", corTagCount + "");
            //正确率
            resultMap.put("accuracy", CastUtil.formatDec(sysTagCount - corTagCount, sysTagCount + addTagCount));
            //漏识率
            resultMap.put("leakage", CastUtil.formatDec(addTagCount, tagCount));
        } else {
            resultMap.put("tagType", "0");
            resultMap.put("tagName", "-");
            resultMap.put("sysTagCount", "-");
            resultMap.put("addTagCount", "-");
            resultMap.put("corTagCount", "-");
            //正确率
            resultMap.put("accuracy", "-");
            //漏识率
            resultMap.put("leakage", "-");
        }
    }

    private Map<String, String> formatSysResultAll(HttpServletRequest request) {
        Map<String, String> resultMap = new HashMap<>();
        String provinceCode = Strings.isNullOrEmpty(request.getParameter("provinceCode")) ? "-" : request.getParameter("provinceCode");
        resultMap.put("provinceCode", provinceCode);
        Map<String, Integer> countMap = sumSysTagAll(request);
        contMap(resultMap, countMap, "sys");
        return resultMap;
    }

    private Map<String, String> formatTelResultAll(HttpServletRequest request) {
        Map<String, String> resultMap = new HashMap<>();
        String provinceCode = Strings.isNullOrEmpty(request.getParameter("provinceCode")) ? "-" : request.getParameter("provinceCode");
        resultMap.put("provinceCode", provinceCode);
        Map<String, Integer> countMap = sumTelTagAll(request);
        contMap(resultMap, countMap, "tel");
        return resultMap;
    }

    private Map<String, Integer> sumTelTagAll(HttpServletRequest request) {
        List<Source> allTags = new ArrayList<>();
        //单词查询条数
        int excleMax = ConfigHelper.getInt("export.data.sheet.max.number", 1000);
        // 系统打标量
        String[] includes = new String[]{"serialNumber", "callTags"};
        //总条数
        Integer sum = SystemStatic.crud.queryQBuilderAllByMes(SystemStatic.AUDIO_ES_INDEX,
                SystemStatic.AUDIO_ES_TYPE,
                getTelTagAllQue(request)
        );
        List<Integer> pageTout1 = TaskUtil.formatSum(sum, excleMax);//todo最后一个数字需要特殊处理:6022
        for (Integer aPageTout : pageTout1) {
            List<String> docList = SystemStatic.crud.queryQBuilderByMes(
                    SystemStatic.AUDIO_ES_INDEX,
                    SystemStatic.AUDIO_ES_TYPE,
                    aPageTout,
                    excleMax,
                    getTelTagAllQue(request),
                    includes
            );
            if (docList.isEmpty()) continue;
            allTags.addAll(esUtil.strs2Entitys(docList));
        }
        return formatResMap(allTags, BaseEntity.PROTYPE_ZX, "", "");
    }

    private List<Map<String, String>> formatTagIdsResult(
            List<BusTag> tagList,
            HttpServletRequest request, String tagType
    ) {
        String provinceCode = Strings.isNullOrEmpty(request.getParameter("provinceCode")) ? "-" : request.getParameter("provinceCode");
        List<Map<String, String>> resultList = new ArrayList<>();
        for (BusTag tag : tagList) {
            Map<String, String> resultMap = new HashMap<>();
            Map<String, Integer> countMap = sumSysAndTelTags(tag.getContent(), request, Integer.parseInt(tagType));
            String type = "0".equals(tagType) ? "tel" : "sys" ;
            contMap(resultMap, countMap, type);
            resultMap.put("provinceCode", provinceCode);
            resultMap.put("tagId", tag.getId() + "");
            resultMap.put("tagName", tag.getContent());
            resultList.add(resultMap);
        }
        return resultList;
    }

    @Override
    public Map<String, List<Map<String, String>>> getTagQuery(HttpServletRequest request, String type) {
        String sysTagIds = request.getParameter("sysTagIds");//系统标签_标签ids
        String telTagIds = request.getParameter("telTagIds");//话务小结_标签ids
        List<BusTag> sysTagMap = new ArrayList<>();//系统标签_标签ids
        List<BusTag> telTagMap = new ArrayList<>();//话务小结_标签ids
        if (!Strings.isNullOrEmpty(sysTagIds)) {
            for (String tagId : sysTagIds.split(",")) {
                sysTagMap.add(tagMapper.selectByPrimaryKey(Long.parseLong(tagId)));
            }
        }
        if (!Strings.isNullOrEmpty(telTagIds)) {
            for (String tagId : telTagIds.split(",")) {
                telTagMap.add(tagMapper.selectByPrimaryKey(Long.parseLong(tagId)));
            }
        }
        List<Map<String, String>> countList = new ArrayList<>();
        Map<String, String> countMap = new HashMap<>();
        Map<String, List<Map<String, String>>> result = new HashMap<>();
        List<Map<String, String>> allResultMap = new ArrayList<>();
        if (sysTagMap.isEmpty() && telTagMap.isEmpty()) {
            allResultMap.add(formatSysResultAll(request));
            allResultMap.add(formatTelResultAll(request));
        } else {
            if (!sysTagMap.isEmpty()) {
                allResultMap.addAll(formatTagIdsResult(sysTagMap, request, BaseEntity.PROTYPE_SYS + ""));
            }
            if (!telTagMap.isEmpty()) {
                allResultMap.addAll(formatTagIdsResult(telTagMap, request, BaseEntity.PROTYPE_ZX + ""));
            }
        }

        countMap.put("count", Integer.toString(allResultMap.size()));
        countList.add(countMap);
        result.put("countList", countList);
        result.put("resultList", allResultMap);
        return result;
    }

    @Override
    public HtmlResult getTagCount(HttpServletRequest request) {
        Map<String, List<Map<String, String>>> result = getTagQuery(request, "search");
        List<Map<String, String>> resultList = result.get("resultList");
        return HtmlResult.success(resultList, Integer.parseInt(result.get("countList").get(0).get("count")));
    }

    @Override
    public BoolQueryBuilder getQuery(String logTxt, HttpServletRequest request) {
        Map<String, String[]> params = new HashMap<>(request.getParameterMap());
        String provinceCode = request.getParameter("provinceCode");//省份
        if (!Strings.isNullOrEmpty(provinceCode)) {
            String customerlocs = request.getParameter("customerloc");//归属地
            params.put("customerloc", null);
            params.put("provinceCode", new String[]{JSON.toJSONString(searchPubMet.strFormatJson(provinceCode, customerlocs))});
        }
        return searchPubMet.getQuery(logTxt, params, request);
    }

    @Override
    public HtmlResult searchData(HttpServletRequest request) throws InvocationTargetException, IllegalAccessException {
        String logTxt = "【音频检索方法Impl】";
        logger.info(logTxt);
        Map<String, String[]> params = new HashMap<>(request.getParameterMap());
        String provinceCode = request.getParameter("provinceCode");//省份
        if (!Strings.isNullOrEmpty(provinceCode)) {
            params.put("customerloc", null);
            String customerlocs = request.getParameter("customerloc");//归属地
            params.put("provinceCode", new String[]{JSON.toJSONString(searchPubMet.strFormatJson(provinceCode, customerlocs))});
        }
        return searchPubMet.searchData(logTxt, params, request);
    }

    //根据标签名称查询系统标签条件
    private BoolQueryBuilder getSysTagQueByName(HttpServletRequest request, String query) {
        BoolQueryBuilder queryBuilder = new BoolQueryBuilder();
        formStaticQ(request, queryBuilder);
        queryBuilder.must(QueryBuilders.boolQuery()
                .should(
                        QueryBuilders.nestedQuery(
                                "callTags",
                                QueryBuilders.boolQuery()
                                        .must(QueryBuilders.prefixQuery("callTags.tagName", query))
                                        .must(QueryBuilders.matchQuery("callTags.proType", BaseEntity.PROTYPE_ZJ)),
                                ScoreMode.None
                        )
                ).should(
                        QueryBuilders.nestedQuery(
                                "callTags",
                                QueryBuilders.boolQuery()
                                        .must(QueryBuilders.prefixQuery("callTags.tagName", query))
                                        .must(QueryBuilders.matchQuery("callTags.proType", BaseEntity.PROTYPE_SYS)),
                                ScoreMode.None
                        )
                )
        );
        return queryBuilder;
    }

    //根据标签名称查询话务小结标签条件
    private BoolQueryBuilder getTelTagQueByName(HttpServletRequest request, String query) {
        BoolQueryBuilder queryBuilder = new BoolQueryBuilder();
        formStaticQ(request, queryBuilder);
        queryBuilder.must(
                QueryBuilders.nestedQuery(
                        "callTags",
                        QueryBuilders.boolQuery()
                                .must(QueryBuilders.wildcardQuery("callTags.tagName", query + "*"))
                                .must(QueryBuilders.matchQuery("callTags.proType", BaseEntity.PROTYPE_ZJ)),
                        ScoreMode.None
                )
        );
        return queryBuilder;
    }

    private void formStaticQ(HttpServletRequest request, BoolQueryBuilder queryBuilder) {
        String provinceCode = request.getParameter("provinceCode");
        String citys = request.getParameter("citys");
        String satisfactions = request.getParameter("satisfaction");//满意度
        String customerLevels = request.getParameter("customerLevels");//客户星级
        String reCallFlag = request.getParameter("reCallFlag");//是否重复来电
        String callStartTime = request.getParameter("callStartTime");
        String callEndTime = request.getParameter("callEndTime");
        PubMethod.formatTime(queryBuilder, callStartTime, callEndTime);
        if (!Strings.isNullOrEmpty(provinceCode)) {
            BoolQueryBuilder proQ = new BoolQueryBuilder();
            proQ.must(QueryBuilders.matchQuery("voiceInfo.provinceCode", provinceCode));
            //归属地为空时，为直辖市
            if (!Strings.isNullOrEmpty(citys)) {
                PubMethod.formatPC(proQ, Arrays.asList(citys.split(",")));
            }
            queryBuilder.must(proQ);
        }
        //重复来电
        if (!Strings.isNullOrEmpty(reCallFlag)) {
            queryBuilder.must(QueryBuilders.matchQuery("voiceInfo.reCallFlag", reCallFlag));
        }
        //客户星级
        esUtil.formatShouldQ(customerLevels, queryBuilder, "voiceInfo.customerLevel");
        //满意度
        esUtil.formatShouldQ(satisfactions, queryBuilder, "voiceInfo.satisfaction");
        //数据权限
        esUtil.formatQ(queryBuilder, null);
    }

    //获取所有系统标签Tag查询条件
    private BoolQueryBuilder getSysTagAllQue(HttpServletRequest request) {
        BoolQueryBuilder queryBuilder = new BoolQueryBuilder();
        formStaticQ(request, queryBuilder);
        queryBuilder
                .should(
                        QueryBuilders.nestedQuery(
                                "callTags",
                                QueryBuilders.matchQuery("callTags.proType", BaseEntity.PROTYPE_ZJ),
                                ScoreMode.None
                        )
                ).should(
                        QueryBuilders.nestedQuery(
                                "callTags",
                                QueryBuilders.matchQuery("callTags.proType", BaseEntity.PROTYPE_SYS),
                                ScoreMode.None
                        )
        );
        return queryBuilder;
    }

    //获取所有系统标签Tag查询条件
    private BoolQueryBuilder getTelTagAllQue(HttpServletRequest request) {
        BoolQueryBuilder queryBuilder = new BoolQueryBuilder();
        formStaticQ(request, queryBuilder);
        queryBuilder.must(
                QueryBuilders.nestedQuery(
                        "callTags",
                        QueryBuilders.matchQuery("callTags.proType", BaseEntity.PROTYPE_ZX),
                        ScoreMode.None
                )
        );
        return queryBuilder;
    }
}
